#include "clientgui.h"
#include <QDebug>
#include "globaldefinition.h"
#include "initvalues.h"
#include "dcpp/Client.h"
#include "dcpp/ChatMessage.h"
#include "favoritehubsaver.h"

using namespace dcpp;
using namespace std;

ClientGUI::ClientGUI(Client *client, QObject *parent) :
    QObject(parent),
    m_client(client)
{
    qDebug()<<Q_FUNC_INFO<<_q(client->getAddress());
    client->addListener(this);
}

/** Шаблон оборачивающий код в try-catch.
 *
 * При возникновении исключения сморит какой тип данных дожно было
 * вернуть лямбда-выражение и создаёт пустой объект данного типа.*/
template <typename Function>
inline auto returnEmptyIfThrow(Function f) -> decltype(f()){
    try{
        return f();
    }catch(...){
        return decltype(f())();
    }
}

const QStringList &ClientGUI::chat() const noexcept{
    try{
        return m_chat;
    }catch(...){
        return QStringList();
    }
}

QString ClientGUI::password() const noexcept{
    return returnEmptyIfThrow([&]() {
                              return _q(m_client->getPassword());
});
}

void ClientGUI::setPassword(const QString &password) noexcept{    
    return returnEmptyIfThrow([&]() {
        if(password != this->password()){
            return m_client->setPassword(_tq(password));
            saveToFavoriteHubParam(FavHubModif::password, password);
            emit passwordChange();
        }
    });
}

QString ClientGUI::encoding() const noexcept{
    return returnEmptyIfThrow([&]() {
                              return  _q(m_client->getEncoding());
});
}

void ClientGUI::setEncoding(const QString &encoding) noexcept{
    return returnEmptyIfThrow([&]() -> void {
        if(encoding != this->encoding())    {
            m_client->setEncoding(_tq(encoding));
            saveToFavoriteHubParam(FavHubModif::encoding, encoding);
            emit encodingChange();
        }
    });
}

QString ClientGUI::currentNick() const noexcept{
    return returnEmptyIfThrow([&]() {
                              return _q(m_client->getCurrentNick());
});
}

void ClientGUI::setCurrentNick(const QString &currentNick) noexcept{
    qDebug()<<Q_FUNC_INFO<<__LINE__<<currentNick;
    return returnEmptyIfThrow([&]() -> void {
        qDebug()<<Q_FUNC_INFO<<__LINE__<<currentNick;
        if(currentNick != this->currentNick())    {
            qDebug()<<Q_FUNC_INFO<<__LINE__<<currentNick;
            m_client->setCurrentNick(_tq(currentNick));
            saveToFavoriteHubParam(FavHubModif::nick, currentNick);
            emit currentNickChange();
        }
    });
}

QString ClientGUI::currentDescription() const noexcept{
    return returnEmptyIfThrow([&]() {
                              return  _q(m_client->getCurrentDescription());
});
}

void ClientGUI::setCurrentDescription(const QString currentDescription) noexcept{
    return returnEmptyIfThrow([&]() -> void {
        if(currentDescription != this->currentDescription())    {
            m_client->setCurrentDescription(currentDescription.toAscii().data());
            saveToFavoriteHubParam(FavHubModif::description, currentDescription);
            emit currentDescriptionChange();
        }
    });
}

QString ClientGUI::port() const noexcept{
    return returnEmptyIfThrow([&]() {
                              return  _q(m_client->getPort());
});
}

QString ClientGUI::ip() const noexcept{
    return returnEmptyIfThrow([&]() {
                              return  _q(m_client->getIp());
});
}

QString ClientGUI::address() const noexcept{
    return returnEmptyIfThrow([&]() {
                              return  _q(m_client->getAddress());
});
}

QString ClientGUI::hubName() const noexcept{
    return returnEmptyIfThrow([&]() {
                              return  _q(m_client->getHubName());
});
}



// Слушатель dcpp::ClientManager

void ClientGUI::on(ClientListener::Connecting, Client * client) noexcept{
}

void ClientGUI::on(ClientListener::Connected, Client * client) noexcept{
}

void ClientGUI::on(ClientListener::UserUpdated, Client * client, const OnlineUser &) noexcept{
}

void ClientGUI::on(ClientListener::UsersUpdated, Client * client, const OnlineUserList &) noexcept{
}

void ClientGUI::on(ClientListener::UserRemoved, Client * client, const OnlineUser &) noexcept{
}

void ClientGUI::on(ClientListener::Redirect, Client * client, const string &newAdr) noexcept{
}

void ClientGUI::on(ClientListener::Failed, Client * client, const string & err) noexcept{
}

void ClientGUI::on(ClientListener::GetPassword, Client * client) noexcept{
}

void ClientGUI::on(ClientListener::HubUpdated, Client * client) noexcept{
    try{
        if(client == this->m_client){
            qDebug()<<Q_FUNC_INFO<<trUtf8("Изменены данные хаба %0 по адресу %1").arg(client->getHubName().c_str()).arg(client->getAddress().c_str());
            emitAllChanged();
        }
    }catch(...){
        STANDART_ERROR_MASSAGE;
    }
}

void ClientGUI::on(ClientListener::Message, Client * client, const ChatMessage &msg) noexcept{
    if(client == m_client){
        if(m_chat.size() == InitValues::getInstance()->maxChatSize())
            m_chat.removeFirst();
        m_chat<<_q(msg.message);
        emit chatChange();
    }
}

void ClientGUI::on(ClientListener::StatusMessage, Client * client, const string &msg, int n) noexcept{
}

void ClientGUI::on(ClientListener::HubUserCommand, Client * client, int n1, int n2, const string & str1, const string & str2) noexcept{
}

void ClientGUI::on(ClientListener::HubFull, Client * client) noexcept{
}

void ClientGUI::on(ClientListener::NickTaken, Client * client) noexcept{
}

void ClientGUI::on(ClientListener::SearchFlood, Client * client, const string & msg) noexcept{
}

void ClientGUI::on(ClientListener::NmdcSearch, Client * client, const string & str1, int n1, int64_t n2, int n3, const string & str2) noexcept{
}

void ClientGUI::on(ClientListener::AdcSearch, Client * client, const AdcCommand &, const CID &) noexcept{
}

void ClientGUI::emitAllChanged(){
    emit passwordChange();
    emit encodingChange();
    emit currentNickChange();
    emit currentDescriptionChange();
    emit portChange();
    emit ipChange();
    emit addressChange();
    emit hubNameChange();
}

void ClientGUI::saveToFavoriteHubParam(const QString &name, const QString &value){
    FavoriteHubModifer::getInstance()->add(_q(m_client->getAddress()), name, value);
    FavoriteHubModifer::getInstance()->save(_q(m_client->getAddress()));
}

ClientGUI::~ClientGUI()
{
    qDebug()<<Q_FUNC_INFO<<_q(m_client->getAddress());
}
